/**
 * 批处理作业构建工厂
 * 负责构建和配置批处理作业
 */
@Slf4j
public class BatchJobBuilderFactory {

    // 读取器映射,key为读取器类名
    private final Map<String, ItemReader<?>> readerMap;
    
    // 处理器映射,key为处理器类名
    private final Map<String, ItemProcessor<?, ?>> processorMap;
    
    // 写入器映射,key为写入器类名
    private final Map<String, ItemWriter<?>> writerMap;
    
    // 批处理配置属性
    private final BatchProperties properties;
    
    // 持久化提供者解析器
    private final PersistenceProviderResolver persistenceProviderResolver;

    /**
     * 构造函数
     * @param readers 所有可用的读取器列表
     * @param processors 所有可用的处理器列表
     * @param writers 所有可用的写入器列表
     * @param properties 批处理配置属性
     * @param persistenceProviderResolver 持久化提供者解析器
     */
    public BatchJobBuilderFactory(
            List<ItemReader<?>> readers,
            List<ItemProcessor<?, ?>> processors,
            List<ItemWriter<?>> writers,
            BatchProperties properties,
            PersistenceProviderResolver persistenceProviderResolver) {
        // 初始化读取器映射
        this.readerMap = readers.stream()
                .collect(Collectors.toMap(r -> r.getClass().getSimpleName(), Function.identity()));
        // 初始化处理器映射
        this.processorMap = processors.stream()
                .collect(Collectors.toMap(p -> p.getClass().getSimpleName(), Function.identity()));
        // 初始化写入器映射
        this.writerMap = writers.stream()
                .collect(Collectors.toMap(w -> w.getClass().getSimpleName(), Function.identity()));
        this.properties = properties;
        this.persistenceProviderResolver = persistenceProviderResolver;
    }

    /**
     * 构建批处理作业
     * @param jobName 作业名称
     * @param jobRepository 作业仓库
     * @param transactionManager 事务管理器
     * @return 构建好的作业
     */
    public Job buildJob(String jobName, JobRepository jobRepository, 
            PlatformTransactionManager transactionManager) {
        // 获取作业配置
        JobConfig config = properties.getJobs().stream()
                .filter(job -> job.getName().equals(jobName))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Job not found: " + jobName));

        // 构建作业
        return new JobBuilder(jobName, jobRepository)
                .start(buildStep(config, jobRepository, transactionManager))
                .listener(new JobExecutionListener() {
                    @Override
                    public void beforeJob(JobExecution jobExecution) {
                        log.info("Starting job: {}", jobName);
                    }

                    @Override
                    public void afterJob(JobExecution jobExecution) {
                        log.info("Job {} completed with status: {}", 
                            jobName, jobExecution.getStatus());
                    }
                })
                .build();
    }

    /**
     * 构建处理步骤
     * @param config 步骤配置
     * @param jobRepository 作业仓库
     * @param transactionManager 事务管理器
     * @return 构建好的处理步骤
     */
    private Step buildStep(JobConfig config, JobRepository jobRepository, 
            PlatformTransactionManager transactionManager) {
        StepBuilder stepBuilder = new StepBuilder(config.getName() + "Step", jobRepository);
        
        // 获取数据源配置
        String dataSourceName = config.getParameters().getOrDefault("dataSource", 
            properties.getPrimary());
            
        // 设置数据源上下文
        DynamicRoutingDataSource.setDataSource(dataSourceName);
        
        try {
            // 获取读取器、处理器和写入器
            ItemReader<?> reader = readerMap.get(config.getReader());
            ItemProcessor<?, ?> processor = processorMap.get(config.getProcessor());
            ItemWriter<?> writer = createWriter(config.getWriter(), dataSourceName);
            
            // 构建步骤
            SimpleStepBuilder<?, ?> step = stepBuilder
                    .<Object, Object>chunk(config.getChunkSize(), transactionManager)
                    .reader(reader)
                    .processor(processor)
                    .writer(writer);
                    
            // 配置跳过策略
            if (config.isSkipLimit()) {
                step.skipLimit(config.getMaxSkipCount())
                    .skip(Exception.class);
            }

            // 配置重试策略
            switch (config.getRetryPolicy()) {
                case SIMPLE:
                    configureSimpleRetry(step);
                    break;
                case EXPONENTIAL_BACKOFF:
                    configureExponentialBackoffRetry(step);
                    break;
            }

            return step.build();
        } finally {
            // 清理数据源上下文
            DynamicRoutingDataSource.clearDataSource();
        }
    }
    
    /**
     * 创建写入器
     * @param writerName 写入器名称
     * @param dataSourceName 数据源名称
     * @return 配置好的写入器
     */
    private ItemWriter<?> createWriter(String writerName, String dataSourceName) {
        ItemWriter<?> writer = writerMap.get(writerName);
        if (writer instanceof DynamicPersistenceAwareWriter) {
            ((DynamicPersistenceAwareWriter) writer).setPersistenceProvider(
                persistenceProviderResolver.getProvider(dataSourceName));
        }
        return writer;
    }

    /**
     * 配置简单重试策略
     * @param step 步骤构建器
     */
    private void configureSimpleRetry(SimpleStepBuilder<?, ?> step) {
        step.retryLimit(properties.getRetry().getMaxAttempts())
            .retry(Exception.class)
            .listener(new RetryListener());
    }

    /**
     * 配置指数退避重试策略
     * @param step 步骤构建器
     */
    private void configureExponentialBackoffRetry(SimpleStepBuilder<?, ?> step) {
        // 创建退避策略
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(properties.getRetry().getBackoffPeriod());
        
        // 配置重试策略
        step.faultTolerant()
            .retryPolicy(new ExponentialBackOffRetryPolicy(backOffPolicy))
            .retry(Exception.class)
            .listener(new RetryListener());
    }
} 